package com.stylesmile.socket.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.ReentrantLock;

public class AsyncHttpServer {

    /**
     * 锁 线程安全处理 ，不处理io操作线程不安全
     */
    private static final ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) throws IOException, InterruptedException {
        // 创建一个固定大小的线程池
        ExecutorService executor = Executors.newFixedThreadPool(10);

        // 创建一个AsynchronousChannelGroup实例
        AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(executor);

        // 创建一个AsynchronousServerSocketChannel实例并将其绑定到指定的端口
        AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open(channelGroup);
        serverChannel.bind(new InetSocketAddress(8080));

        // 为每个连接创建一个CompletionHandler
        CompletionHandler<AsynchronousSocketChannel, Void> acceptHandler = new CompletionHandler<AsynchronousSocketChannel, Void>() {
            @Override
            public void completed(AsynchronousSocketChannel socketChannel, Void attachment) {
                serverChannel.accept(null, this); // 接受下一个连接
                handleConnection(socketChannel); // 处理当前连接
            }

            @Override
            public void failed(Throwable exc, Void attachment) {
                System.out.println("Failed to accept connection: " + exc.getMessage());
            }
        };

        // 将CompletionHandler添加到AsynchronousServerSocketChannel
        serverChannel.accept(null, acceptHandler);

        // 等待用户输入，以便在按下Enter键时关闭服务器
        System.in.read();

        // 关闭连接和AsynchronousChannelGroup
        serverChannel.close();
        channelGroup.shutdown();
    }

    private static void handleConnection(AsynchronousSocketChannel socketChannel) {
        lock.lock();
        try {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            socketChannel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
                @Override
                public void completed(Integer result, ByteBuffer attachment) {
                    if (result == -1) {
                        try {
                            socketChannel.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        return;
                    }

                    attachment.flip();
                    // 处理请求数据，例如解析HTTP请求并生成响应
                    // ...


                    // 清空缓冲区并继续读取数据
                    attachment.clear();
                    socketChannel.read(attachment, attachment, this);

                    // Process the request and send response
                    String response = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!";
                    ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());
                    Future<Integer> writeResult = socketChannel.write(responseBuffer);
                    try {
                        writeResult.get();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    } catch (ExecutionException e) {
                        throw new RuntimeException(e);
                    }
                    try {
                        socketChannel.close();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }

                @Override
                public void failed(Throwable exc, ByteBuffer attachment) {
                    System.out.println("Failed to read data: " + exc.getMessage());
                    try {
                        socketChannel.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        } finally {
            lock.unlock();
        }

    }
}
